package com.example.javabighw.controller;

import com.example.javabighw.dao.UserDao;
import com.example.javabighw.entity.User;
import com.google.gson.Gson;

import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import java.io.IOException;
import java.util.*;

@Controller
public class LoginController {
    @Value("${clientId}")
    public String clientId;
    @Value("${callback}")
    public String callback;
    @Value("${clientSecret}")
    public String clientSecret;
    private HashMap user_info_hashMap;

    @Autowired
    UserDao userDao;

    @RequestMapping("/gitee/login")
    public String login() {
        String url = "https://gitee.com/oauth/authorize?client_id=%s" + "&redirect_uri=%s&response_type=code";
        url = String.format(url, clientId, callback);
        return "redirect:" + url;
    }

    @RequestMapping("/callback")
    public String callback() {
        return "about.html";
    }

    @ResponseBody
    @RequestMapping("/gitee/callback")
    public HashMap<String, Object> gitee_callback(@RequestParam("code") String code) {
        HashMap<String, Object> ret = new HashMap<>();
        System.out.println("code: " + code);

        HttpClient httpClient = HttpClients.createDefault();
        HttpPost httpPost = new HttpPost("https://gitee.com/oauth/token");
        List<NameValuePair> params = new ArrayList<>(5);

        params.add(new BasicNameValuePair("grant_type", "authorization_code"));
        params.add(new BasicNameValuePair("code", code));
        params.add(new BasicNameValuePair("client_id", clientId));
        params.add(new BasicNameValuePair("redirect_uri", callback));
        params.add(new BasicNameValuePair("client_secret", clientSecret));

        String resp_json;
        try {
            httpPost.setEntity(new UrlEncodedFormEntity(params, "utf-8"));
            HttpResponse httpResponse = httpClient.execute(httpPost);
            resp_json = EntityUtils.toString(httpResponse.getEntity(), "utf-8");
            System.out.println(resp_json);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

        Gson gson = new Gson();
        HashMap hashMap = gson.fromJson(resp_json, HashMap.class);
        String access_token = hashMap.get("access_token").toString();
        System.out.println("access_token: " + access_token);

        String uri = "https://gitee.com/api/v5/user?access_token=" + access_token;
        HttpGet httpGet = new HttpGet(uri);
        String user_info = null;
        try {
            CloseableHttpResponse httpResponse = (CloseableHttpResponse) httpClient.execute(httpGet);
            // get user info from https://gitee.com
            if (httpResponse.getStatusLine().getStatusCode() == 200) {
                user_info = EntityUtils.toString(httpResponse.getEntity(), "utf-8");
                user_info_hashMap = gson.fromJson(user_info, HashMap.class);
                System.out.println("user_info: " + user_info);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        if (!userDao.isExistByGiteeId(user_info_hashMap.get("id").toString())) {
            userDao.createUserFromGitee(
                    user_info_hashMap.get("id").toString(),
                    user_info_hashMap.get("name").toString(),
                    hashMap.get("access_token").toString(),
                    hashMap.get("refresh_token").toString(),
                    user_info_hashMap.get("avatar_url").toString());
            ret.put("session_key", userDao.getUserByGiteeId(user_info_hashMap.get("id").toString()).getSessionKey());
        }

        return ret;
    }

    @ResponseBody
    @RequestMapping("/gitee/getInfo")
    public Map getInfo(@RequestParam("skey") String skey) {
        System.out.println("returned session key: " + skey);

        Map<String, Object> result = new HashMap<>();
        Gson gson = new Gson();
        String user_info = null;
        try {
            User user = userDao.getUserBySessionKey(skey);
            String access_token = user.getGiteeAccessToken();
            String uri = "https://gitee.com/api/v5/user?access_token=" + access_token;
            HttpClient httpClient = HttpClients.createDefault();
            HttpGet httpGet = new HttpGet(uri);
            try {
                CloseableHttpResponse httpResponse = (CloseableHttpResponse) httpClient.execute(httpGet);
                // get user info from https://gitee.com
                if (httpResponse.getStatusLine().getStatusCode() == 200) {
                    user_info = EntityUtils.toString(httpResponse.getEntity(), "utf-8");
                    HashMap json = gson.fromJson(user_info, HashMap.class);
                    System.out.println("user_info: " + user_info);
                    List<String> field = Arrays.asList("id", "name", "html_url",
                            "followers", "following", "stared", "created_at", "updated_at");
                    for (int i = 0; i < field.toArray().length; i++) {
                        result.put(field.get(i), json.get(field.get(i)).toString());
                    }
                    result.put("avatar_url", user.getGiteeAvatarUrl());
                    result.put("session_key", user.getSessionKey());
                    result.put("state_code", 200);
                } else {
                    result.put("state_code", 302);
                }
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        } catch (Exception e) {
            result.put("state_code", 302);
            return result;
        }

        return result;
    }

}
